package higher;

import java.nio.ByteBuffer;

import storage.storageMgr;

import buffer.BufMgr;

public class DBMgr {
	private static String inUse = null;
	private BufMgr combMgr;
	private storageMgr comsMgr;
	
	private String dbName = "noname";
	private int orgSize;
	private byte[] bitmap;
	
	public DBMgr(BufMgr b, storageMgr s){
		combMgr = b;
		comsMgr = s;
		orgSize = (int) (comsMgr.scale()/ 8);
		bitmap = new byte[ orgSize ];
	}	
	
	public boolean createDB(String dbname){
		comsMgr.newDB(dbname);
		dbName = dbname;
		for(int i = 0; i < orgSize; i++) bitmap[i] = 0;
		bitmap[0] = (byte) (1 << 7);
		
		ByteBuffer bb = ByteBuffer.allocate( comsMgr.pageSize() );
		bb.put(bitmap);
		comsMgr.writePage(dbName, 0, bb);
		
		return true;
	}
	
	public boolean dropDB(String dbname){
		comsMgr.destroyDB(dbname);
		combMgr.flushAll(dbname);
		return true;
	}
	
	public boolean openDB(String dbname){
		if (inUse != null ) throw new RuntimeException(inUse + " not closed ");
		if ( comsMgr.canOpen(dbname) == 1){
			inUse = dbname;
			dbName = dbname;
			
			ByteBuffer bb = ByteBuffer.allocate( comsMgr.pageSize() );
			comsMgr.readPage(dbName, 0, bb);
			bb.rewind();
			bb.get(bitmap);
			return true;
		}
		else
		return false;
	}
	
	public boolean closeDB(){	
		if (inUse != dbName) throw new RuntimeException(dbName + " not opened ");
		if ( comsMgr.canClose(dbName) == 1){
			
			ByteBuffer bb = ByteBuffer.allocate( comsMgr.pageSize() );
			bb.put(bitmap);
			comsMgr.writePage(dbName, 0, bb);
			
			inUse = null;
			return true;
		}
		else
		return false;
	}
	
	public int allocPage(){
		
		for (int i = 0; i < orgSize; i++){
			if( bitmap[i] < 0xFF ){
				int j = 0;
				int k = bitmap[i];
				int mask = 0x80;
				do {
					if ((mask & k) == 0){
						bitmap[i] |= 1 << (7-j);
						return ( i * 8 + j );
					}
					mask >>= 1;
					j++;
				}
				while( j <= 8 );
			}
		}
		throw new RuntimeException( dbName + " cannot allocate page ");
	}
	
	public boolean deallocPage(int pid){
		if ( pid >= orgSize * 8) throw new RuntimeException( pid + " too large ");
		if ( pid <= 0) throw new RuntimeException( pid + " too small ");
		
		int seg = pid / 8;
		int bit = pid % 8;
		bitmap[seg] &= ~( 0x80 >> bit); 
		
		return true;
	}
	
	public boolean readPage(int pid, ByteBuffer bb){
		if ( pid >= orgSize * 8) throw new RuntimeException( pid + " too large ");
		if ( pid <= 0) throw new RuntimeException( pid + " too small ");
		
		int seg = pid / 8;
		int bit = pid % 8;
		int bits = bitmap[seg];
		if (((bits & (~( 0x80 >> bit)))== 0 )) throw new RuntimeException( pid + " invalid ");
		
		buffer.Buf bf = combMgr.pin(dbName, pid);
		combMgr.rw_page(bf, 0, bb);
		combMgr.unpin(bf, true, true);
		
		return true;
	}
	
	public boolean writePage(int pid, ByteBuffer bb){
		if ( pid >= orgSize * 8) throw new RuntimeException( pid + " too large ");
		if ( pid <= 0) throw new RuntimeException( pid + " too small ");
		
		int seg = pid / 8;
		int bit = pid % 8;
		int bits = bitmap[seg];
		if (((bits & (~( 0x80 >> bit)))== 0 )) throw new RuntimeException( pid + " invalid ");
		
		buffer.Buf bf = combMgr.pin(dbName, pid);
		combMgr.rw_page(bf, 1, bb);
		combMgr.unpin(bf, true, true);
		
		return true;
	}
	
}
